package com.yeyaomai.dksns.flowis.dao.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.mongodb.core.mapreduce.GroupBy;
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Order;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import com.yeyaomai.dksns.flowis.dao.DetailDao;
import com.yeyaomai.dksns.flowis.dao.MongoDBBasicDao;
import com.yeyaomai.dksns.flowis.domain.Today;
import com.yeyaomai.dksns.flowis.domain.flowisdetail.FlowisQueryOrder;
import com.yeyaomai.dksns.flowis.domain.flowisdetail.FlowisStatDetailDTO;
import com.yeyaomai.dksns.flowis.page.PageImplResult;
import com.yeyaomai.dksns.flowis.page.PageRequestOrder;
import com.yeyaomai.dksns.flowis.util.CollectionNames;
import com.yeyaomai.dksns.flowis.util.Globals;
import com.yeyaomai.dksns.flowis.util.ListPropertyAndValueTool;

/**
 * 
 * @author dingtao@yeyaomai.com
 * 
 */

@Component
public class DetailDaoImpl extends MongoDBBasicDao<FlowisStatDetailDTO>
		implements DetailDao {

	//private static Logger logger = LoggerFactory.getLogger(DetailDaoImpl.class);

	@Override
	public Page<FlowisStatDetailDTO> getSplit(FlowisQueryOrder order) {

		Query query = new Query();

		for (Map.Entry<String, String> entry : order.getSort().entrySet()) {
			query.sort().on(entry.getKey(), Order.valueOf(entry.getValue()));
		}

		List<String> includeFields = new ArrayList<String>();
		includeFields.add("ip");
		includeFields.add("access_city");

		query.addCriteria(new Criteria("access_date").gt(order.getStartTime())
				.lt(order.getEndTime()));

		ListPropertyAndValueTool.querySaveCriteria(query, order,
				FlowisStatDetailDTO.class, includeFields);

		PageRequestOrder request = new PageRequestOrder(Integer.parseInt(order
				.getNumber()), order.getPageSize());

		long totalSize = getTotalSize(query, FlowisStatDetailDTO.class);

		query.skip(request.start()).limit(order.getPageSize());

		List<FlowisStatDetailDTO> ps = super.findList(query,
				FlowisStatDetailDTO.class);

		Page<FlowisStatDetailDTO> result = new PageImplResult<FlowisStatDetailDTO>(
				ps, request, totalSize);

		return result;
	}

	@Override
	public void insert(FlowisStatDetailDTO dto) {

		super.save(dto);
	}
	
	@Override
	public void update(Criteria criteria, Update update) {
		
		super.update(criteria, update, FlowisStatDetailDTO.class);
	}

	@Override
	public long getTotalSize(Query query, Class<FlowisStatDetailDTO> document) {
		return super.count(query, document);
	}

	@Override
	public List<FlowisStatDetailDTO> getLastNumberByCondition(
			LinkedHashMap<String, String> conditionArgs) {

		Query query = new Query();

		query.sort().on("access_date", Order.DESCENDING);

		for (Map.Entry<String, String> singleArg : conditionArgs.entrySet()) {
			query.addCriteria(new Criteria(singleArg.getKey()).is(singleArg
					.getValue()));
		}
		return super.findList(query, FlowisStatDetailDTO.class);
	}

	@Override
	public <T> GroupByResults<T> group(Criteria criteria, String key, String map,String reduce, Class<T> clas) {
		
		return mongoTemplate.group(criteria, CollectionNames.FLOWISDETAIL, GroupBy.key(key).initialDocument(map).reduceFunction(reduce), clas);
	}
	
	@Override
	public <T> MapReduceResults<T> groupMapReduce(Query query, String map,String reduce, Class<T> clas) {
		
		return mongoTemplate.mapReduce(query,  CollectionNames.FLOWISDETAIL, map, reduce, clas);
	}
	
	@Override
	public List<FlowisStatDetailDTO> findList(Criteria criteria) {
		
		return super.findList(criteria, FlowisStatDetailDTO.class);
	}
	
	@Override
	public List<FlowisStatDetailDTO> findList(Query query) {
		
		return super.findList(query, FlowisStatDetailDTO.class);
	}
	
	@Override
	public FlowisStatDetailDTO findOne(Query query)
	{
		return super.findOne(query, FlowisStatDetailDTO.class);
	}
	
	@Override
	public <T> GroupByResults<T> groups(Criteria criteria, String map,
			String reduce, Class<T> clas, String... key) {
		// TODO Auto-generated method stub
		return mongoTemplate.group(criteria, CollectionNames.FLOWISDETAIL, GroupBy.key(key).initialDocument(map).reduceFunction(reduce), clas);
	}

	@Override
	public <T> void delete(Query query, Class<T> clas){
		
		mongoTemplate.remove(query, clas);
	}

	@Override
	public Today findFlowisStatDetailDTOByTime(Date date) {
		String formDate = Globals.FORMAT_TYPE_A.format(date)+" 00:00:00";
		String toDate = Globals.FORMAT_TYPE_E.format(date);
			Today today = new Today();
			today.setDkId(1);
			Integer visitCount = this.getPageViewByTime(formDate, toDate);
			today.setVisitCount(visitCount);
			Integer uniqueCount = this.getUVByTime(formDate, toDate);
			today.setUniqueHost(uniqueCount);
			Integer ip = this.getIpByTime(formDate, toDate);
			today.setIp(ip);
			Integer newuniqueHost = this.getNewUVByTime(formDate, toDate);
			today.setNewUniqueHost(newuniqueHost);
		    return today;
	}
	
	/**
	 * 定时任务处理PV
	 */
	private int getPageViewByTime(String formDate, String toDate) 
	{
		Query query = new Query(Criteria.where("access_date").gte(formDate)
				.lte(toDate));

		long pvcount = mongoTemplate.count(query, FlowisStatDetailDTO.class);
		return (int)pvcount;
	}
	/**
	 * 定时任务处理UV
	 */
	private int getUVByTime(String formDate, String toDate) {
		String mapFunction = "{ visitCount: 0}";
		String reduceFunction = "function(doc, prev) {prev.visitCount+=1}";
		Criteria criteria = Criteria.where("access_date").gte(formDate).lte(toDate);
		int uvcount = this.group(criteria, CollectionNames.COOKIEID, mapFunction, reduceFunction, FlowisStatDetailDTO.class).getKeys();
		return uvcount;
	}

	/**
	 * 定时任务处理IP
	 */
	private int getIpByTime(String formDate, String toDate) {
		String mapFunction = "{ip: 0}";
		String reduceFunction = "function(doc, prev) {prev.ip+=1}";
		Criteria criteria = Criteria.where("access_date").gte(formDate).lte(toDate);
		int ipcount = this.group(criteria, CollectionNames.IP, mapFunction, reduceFunction, FlowisStatDetailDTO.class).getKeys();
		return ipcount;
	}

	/**
	 * 定时任务处理newuv
	 */
	private int getNewUVByTime(String formDate, String toDate) {
		int newuvcount = 0;
		String mapFunction = "{cookieId: 0}";
		String reduceFunction = "function(doc, prev) {prev.cookieId+=1}";
		Criteria criteria = Criteria.where("access_date").gte(formDate).lte(toDate).and("visitCount").is(1);
		newuvcount = this.group(criteria, CollectionNames.COOKIEID, mapFunction, reduceFunction, FlowisStatDetailDTO.class).getKeys();
		return newuvcount;
	}
}
